package com.example.fileupload.storage;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 存储策略工厂 - 函数式编程风格
 */
@Slf4j
@Component
public class StorageStrategyFactory {
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Value("${storage.strategy:local}")
    private String defaultStorageStrategy;
    
    private Map<StorageStrategy.StorageType, StorageStrategy> strategyMap;
    
    @PostConstruct
    public void init() {
        // 函数式方式收集所有存储策略
        this.strategyMap = applicationContext.getBeansOfType(StorageStrategy.class)
                .values()
                .stream()
                .collect(java.util.stream.Collectors.toMap(
                        StorageStrategy::getStorageType,
                        Function.identity()
                ));
        
        logAvailableStrategies();
    }
    
    /**
     * 获取默认存储策略
     */
    public StorageStrategy getDefaultStrategy() {
        return getStrategy(defaultStorageStrategy)
                .orElseGet(this::getFallbackStrategy);
    }
    
    /**
     * 根据类型获取存储策略
     */
    public Optional<StorageStrategy> getStrategy(String storageType) {
        try {
            StorageStrategy.StorageType type = StorageStrategy.StorageType.of(storageType);
            return Optional.ofNullable(strategyMap.get(type));
        } catch (Exception e) {
            log.warn("无效的存储策略类型: {}", storageType);
            return Optional.empty();
        }
    }
    
    /**
     * 根据枚举类型获取存储策略
     */
    public Optional<StorageStrategy> getStrategy(StorageStrategy.StorageType storageType) {
        return Optional.ofNullable(strategyMap.get(storageType));
    }
    
    /**
     * 获取所有可用的存储策略
     */
    public Map<StorageStrategy.StorageType, StorageStrategy> getAllStrategies() {
        return Map.copyOf(strategyMap);
    }
    
    /**
     * 检查策略是否可用
     */
    public boolean isStrategyAvailable(String storageType) {
        return getStrategy(storageType).isPresent();
    }
    
    /**
     * 函数式方式执行存储操作
     */
    public <T> Optional<T> executeWithStrategy(
            String storageType, 
            Function<StorageStrategy, T> operation) {
        return getStrategy(storageType)
                .map(strategy -> {
                    try {
                        return operation.apply(strategy);
                    } catch (Exception e) {
                        log.error("执行存储操作失败: {}", e.getMessage());
                        throw new RuntimeException("存储操作失败: " + e.getMessage(), e);
                    }
                });
    }
    
    /**
     * 带回退的存储操作
     */
    public <T> Optional<T> executeWithFallback(
            String primaryStorageType,
            Function<StorageStrategy, T> operation,
            Supplier<T> fallback) {
        try {
            return executeWithStrategy(primaryStorageType, operation);
        } catch (Exception e) {
            // 记录主要策略失败，尝试回退方案
            log.warn("主要存储策略失败: {}, 错误: {}, 使用回退方案", primaryStorageType, e.getMessage());
            try {
                return Optional.ofNullable(fallback.get());
            } catch (Exception fallbackError) {
                log.error("回退方案也失败: {}", fallbackError.getMessage());
                return Optional.empty();
            }
        }
    }
    
    /**
     * 获取回退策略
     */
    private StorageStrategy getFallbackStrategy() {
        // 按优先级顺序：本地存储 -> MinIO -> OSS
        return strategyMap.values()
                .stream()
                .filter(strategy -> strategy.getStorageType() == StorageStrategy.StorageType.LOCAL)
                .findFirst()
                .orElseGet(() -> {
                    if (strategyMap.isEmpty()) {
                        throw new RuntimeException("没有可用的存储策略");
                    }
                    return strategyMap.values().iterator().next();
                });
    }
    
    /**
     * 记录可用策略
     */
    private void logAvailableStrategies() {
        log.info("=== 可用存储策略 ===");
        strategyMap.forEach((type, strategy) -> 
                log.info("- {}: {}", type.getValue(), strategy.getClass().getSimpleName()));
        log.info("默认策略: {}", defaultStorageStrategy);
        log.info("==================");
    }
} 